<?php


namespace app\service;


use app\entity\OrderEntity;
use app\entity\PointDetailEntity;
use app\entity\UserEntity;
use app\exception\ErrorCode;
use app\exception\OaException;
use app\models\request\ReqAddShopCart;
use app\models\request\ReqCreateOrder;
use app\models\request\ReqLogistics;
use app\models\request\ReqOrderPage;
use app\models\response\RespOrderDetail;
use app\models\response\RespPage;
use yii\data\Pagination;

class OrderService
{
    private $CART_CACHE = "cart_cache_";
    private static $USER_STOCK_CACHE = "user_stock_cache_";

    public function findByUid($userId){
        $entity = OrderEntity::find()->where(["user_id"=>$userId,"del_flag"=>0])->one();
        return $entity;
    }


    /**
     * @param ReqAddShopCart $req
     * @return bool
     */
    public function addCart(ReqAddShopCart $req){
       $redis = UserService::getRedis();
       $redis->hSet($this->CART_CACHE.$req->getUserId(), $req->getGoodsId(), $req->getNum());
       return true;
    }

    /**
     * @param $userId
     * @param $goodsId
     * @param $num
     * @return bool
     */
    public static function addUserStock($userId,$goodsId,$num){
        $redis = UserService::getRedis();
        $redis->hincrby(self::$USER_STOCK_CACHE.$userId, $goodsId, $num);
        return true;
    }

    public static function getUserStock($userId,$goodsId){
        $redis = UserService::getRedis();
        $res = $redis->hget(self::$USER_STOCK_CACHE.$userId, $goodsId);
        if (!$res) return 0;
        return $res;
    }

    /**
     * @param $orderNo
     * @param $userId
     * @return array|\yii\db\ActiveRecord|OrderEntity
     * @throws OaException
     */
    public function findByOrderNoAndUserId($orderNo,$userId) {
        $entity = OrderEntity::find()->where(["order_no"=>$orderNo,"user_id"=>$userId,"del_flag"=>0])->one();
        if(!$entity) {
            throw new OaException(ErrorCode::ORDER_NOT_404);
        }
        return $entity;
    }

    /**
     * @param ReqCreateOrder $req
     * @throws \app\exception\OaException
     */
    public function createOrder(ReqCreateOrder $req){
        $service = new AddressService();
        $addressInfo = $service->findByIdAndUserId($req->getAddressId(),$req->getUserId());
        $goodsInfoArr = [];
        foreach ($req->getGoodsList() as $r) {
            if ($r["num"]<=0)   throw new OaException(ErrorCode::ORDER_ERR);
            isset($goodsInfoArr[$r["goodsId"]])?$goodsInfoArr[$r["goodsId"]]+=$r["num"]:$goodsInfoArr[$r["goodsId"]]=$r["num"];
        }
        $goodsIdList = array_keys($goodsInfoArr);

        //当前商品信息
        $service = new GoodsService();
        $goodsList = $service->findByIdArr($goodsIdList);

        if (count($goodsList) != count($goodsIdList)) {
            throw new OaException(ErrorCode::GOODS_INFO_ERR);
        }
        //判断商品库存是否满足
        $totalNeedPoints = 0;
        $payGoodsInfo = [];

        foreach ($goodsList as $r) {
            if ($r->getStockNum()<$goodsInfoArr[$r->getId()]) {
                throw new OaException(ErrorCode::OUT_OF_STOCK);
            }
            $totalNeedPoints += ($r->getNeedPoints()*$goodsInfoArr[$r->getId()]);
            $payGoodsInfo[] = [
                "goodsId"=>$r->getId(),
                "goodName"=>$r->getGoodsName(),
                "pic"=>$r->getPic(),
                "barcode"=>$r->getBarcode(),
                "num"=>$goodsInfoArr[$r->getId()],
                "needPoints"=>$r->getNeedPoints()
            ];
            $exchangedNum = self::getUserStock($req->getUserId(),$r->getId());

            if ($r->getExchangeNum() < $exchangedNum+$goodsInfoArr[$r->getId()] ) {
                throw new OaException(["10006"=>$r->getGoodsName()."该商品已经超过兑换次数"]);
            }

        }
        //判断是否有足够jf
        if (!$totalNeedPoints) throw new OaException(ErrorCode::ORDER_ERR);
        $userService = new UserService();
        $userEntity = $userService->findById($req->getUserId());
        if ($userEntity->getIsExchange()) {
            throw new OaException(ErrorCode::EX_AL_READY);
        }
        if ($totalNeedPoints > $userEntity->getUserPoints()) throw new OaException(ErrorCode::OUT_OF_POINT);


        $connection = UserEntity::getDb();
        $transaction = $connection->beginTransaction();
        $orderNo = "EX".$this->getRandNo();


        try {
//            $sql = "update shop_user  set user_points = user_points-".$totalNeedPoints." ,update_time= CURRENT_TIMESTAMP where id = ".$req->getUserId()." and del_flag=0 and user_points-".$totalNeedPoints.">=0";
            $sql = "update shop_user  set user_points = 0,is_exchange=1 ,update_time= CURRENT_TIMESTAMP where id = ".$req->getUserId()." and del_flag=0 and user_points-".$totalNeedPoints.">=0";

            $res = $connection->createCommand($sql)->query();
            if (!$res->getRowCount())   throw new \Exception("积分更新有误，请重试");

            //写入明细表
            $obj = new PointDetailEntity();
            $obj->setUserId($req->getUserId());
            $obj->setOpType(-1);
            $obj->setPoint($totalNeedPoints);
            $obj->setCurrentPoint($userEntity->getUserPoints());
            $obj->setMarkTxt($orderNo) ;
            $obj->setCreateTime(date("Y-m-d G:i:s"));
            $obj->setUpdateTime(date("Y-m-d G:i:s"));
            $obj->setDelFlag(0);
            $obj->save();

            //写入订单表
            $order = new OrderEntity();
            $order->setStatus(0);
            $order->setUserId($req->getUserId());
            $order->setOrderNo($orderNo);
            $order->setPayPoints($totalNeedPoints);
            $order->setCreateTime(date("Y-m-d G:i:s"));
            $order->setUpdateTime(date("Y-m-d G:i:s"));
            $order->setDelFlag(0);
            $order->setGoodsInfo(json_encode($payGoodsInfo,JSON_UNESCAPED_UNICODE));
            $order->setAddressInfo(json_encode([
                "receivePhone"=>$addressInfo->getReceivePhone(),
                "receiveName"=>$addressInfo->getReceiveName(),
                "province"=>$addressInfo->getProvince(),
                "city"=>$addressInfo->getCity(),
                "district"=>$addressInfo->getDistrict(),
                "detailDddress"=>$addressInfo->getDetailAddress(),
            ],JSON_UNESCAPED_UNICODE));
            $order->save();
            //扣除库存
            foreach ($payGoodsInfo as $r) {
                $sql = "update shop_goods  set stock_num = stock_num-".$r["num"]." ,update_time= CURRENT_TIMESTAMP where id = ".$r["goodsId"]." and del_flag=0 and stock_num-".$r["num"].">=0";
                $res = $connection->createCommand($sql)->query();
                if (!$res->getRowCount())   throw new \Exception("商品库存更新异常，请重试");
            }

/*            foreach ($goodsInfoArr as $goodsId=>$num) {

                self::addUserStock($req->getUserId(),$goodsId,$num);
            }*/
            $transaction->commit();
        } catch (\Throwable $e) {
            $transaction->rollBack();
            throw new OaException(["10007"=>$e->getMessage()]);
        }
        return true;
    }

    /**
     * @param ReqOrderPage $req
     * @return RespPage
     */
    public function listPage(ReqOrderPage  $req) {
        $data = OrderEntity::find()->where(["del_flag"=>0,"user_id"=>$req->getUserId()])->orderBy("id desc");
        if ($req->getKeyword()) {
            $data->andWhere(['like', 'goods_info', $req->getKeyword()]);
        }
        if ($req->getStatus()) {
            $data->andWhere(["status"=>$req->getStatus()-1]);
        }

        $pages = new Pagination(['totalCount' =>$data->count(), 'pageSize' => $req->getPageSize(),'page'=>$req->getPageNo()-1]);
        /**@var $entities OrderEntity[]*/
        $entities = $data->offset($pages->getOffset())->limit($pages->getLimit())->all();
        $list = [];

        foreach ($entities as $entity) {
            $resp = new RespOrderDetail();
            $resp->setGoodsInfo(json_decode($entity->getGoodsInfo()));
            $resp->setAddressInfo(json_decode($entity->getAddressInfo()));
            $resp->setExpressNo($entity->getExpressNo());
            $resp->setExpressCompanyCode($this->getBtnClassOptions($entity->getExpressCompanyCode()));
//            $resp->setExpressCompanyCode($entity->getExpressCompanyCode());
            $resp->setOrderNo($entity->getOrderNo());
            $resp->setPayPoints($entity->getPayPoints());
            $resp->setStatus($entity->getStatus());
            $resp->setCreateTime(date("Y-m-d G:i:s",strtotime($entity->getCreateTime())));
            $resp->setUpdateTime(date("Y-m-d G:i:s",strtotime($entity->getCreateTime())));
            array_push($list,$resp);
        }





        $resp = new RespPage();
        $resp->setTotal(intval($pages->totalCount));
        $resp->setPageSize($pages->getPageSize());
        $resp->setPageNo($req->getPageNo());
        $resp->setList($list);
        return $resp;
    }


    public function getBtnClassOptions($key){

        $arr =  [
            ""=>"",
            "yuantong" => "圆通速递",
            "zhongtong" => "中通快递",
            "yunda" => "韵达快递",
            "shentong" => "申通快递",
            "jtexpress" => "极兔速递",
            "youzhengguonei" => "邮政快递包裹",
            "shunfeng" => "顺丰速运",
            "ems" => "EMS",
            "jd" => "京东物流",
            "youzhengbk" => "邮政标准快递",
            "debangkuaidi" => "德邦快递",
            "shunfengkuaiyun" => "顺丰快运",
            "debangwuliu" => "德邦",
            "danniao" => "丹鸟",
            "zhongtongkuaiyun" => "中通快运",
            "annengwuliu" => "安能快运",
            "lianhaowuliu" => "联昊通",
            "jingdongkuaiyun" => "京东快运",
            "subida" => "速必达",
            "kuayue" => "跨越速运"
        ];
        return $arr[$key];
    }

    /**
     * @param ReqLogistics $req
     * @return mixed
     * @throws OaException
     */
    public function getLogistics(ReqLogistics $req) {
        $activeRecord = $this->findByOrderNoAndUserId($req->getOrderNo(), $req->getUserId());
        if ($activeRecord->getStatus() == 0) {
            throw new OaException(ErrorCode::ORDER_NOT_FH);
        }
        if ($activeRecord->getStatus()== 1) {
             if (!$activeRecord->getExpressDetail() || time()-strtotime($activeRecord->getUpdateTime())>3600) {
                 $arr = $this->getKuai100($activeRecord->getExpressCompanyCode(), $activeRecord->getExpressNo(), "");
                 foreach ($arr as $r) {
                     if ($r["status"] == "签收") {
                        $activeRecord->setStatus(2);
                     }
                     break;
                 }
                 $activeRecord->setExpressDetail(json_encode($arr));
                 $activeRecord->setUpdateTime(date("Y-m-d G:i:s"));
                 $activeRecord->save();
             }
         }
        return json_decode($activeRecord->getExpressDetail(),true);
    }

    /**
     * @return string
     */
    public function getRandNo(){
        return  date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }


    public function getKuai100($company,$code,$phone){


        //参数设置
        $key = 'LzntZLoc4150';                        // 客户授权key
        $customer = '8B5C9C39CDCC9A0945CA21590FC1BCF0';                   // 查询公司编号
        $param = array(
            'com' => $company,             // 快递公司编码
            'num' => $code,     // 快递单号
            'phone' => $phone,                // 手机号
            'from' => '',                 // 出发地城市
            'to' => '',                   // 目的地城市
            'resultv2' => '1',            // 开启行政区域解析
            'show' => '0',                // 返回格式：0：json格式（默认），1：xml，2：html，3：text
            'order' => 'desc'             // 返回结果排序:desc降序（默认）,asc 升序
        );

        //请求参数
        $post_data = array();
        $post_data['customer'] = $customer;
        $post_data['param'] = json_encode($param, JSON_UNESCAPED_UNICODE);
        $sign = md5($post_data['param'] . $key . $post_data['customer']);
        $post_data['sign'] = strtoupper($sign);

        $url = 'https://poll.kuaidi100.com/poll/query.do';    // 实时查询请求地址

       /* echo '请求参数：<br/><pre>';
        echo print_r($post_data);
        echo '</pre>';*/

        // 发送post请求
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $result = curl_exec($ch);
        // 第二个参数为true，表示格式化输出json
        $data = json_decode($result, true);
        if (isset($data["status"]) && $data["status"]==200) {
            return $data["data"];
        }
        throw new OaException(["500"=>$data["message"]]);
    }
}